#include "include/config.h"
#include "rel.h"

// dynsym section.
struct DynsymEntry
{
	unsigned int name;
	ptr_t value; // ossym.list value, imported symbols.
	unsigned int size;
	unsigned char info;
	unsigned char other;
	unsigned short shndx;
};

// rel section.
struct RelEntry
{
	ptrdiff_t offset;
	__extension__ enum {
		IMPORT_SYMBOL_DATA_OFFSET = 1,
		IMPORT_SYMBOL_DATA = 6,
		IMPORT_SYMBOL_CODE = 7,
		RELATIVE_TO_BASE = 8,
	} flag : 8;
	unsigned int dynsymIndex : 24;
} __attribute__((packed));

namespace zero
{
void Rel::init(const Elf& elf, bool isPic, const Section& dynSym, const Section& rel)
{
	if (!isPic)
		return;

	const RelEntry* res = reinterpret_cast<const RelEntry*>(rel.begin);
	ptr_t base = elf.begin;
	const DynsymEntry* des = reinterpret_cast<const DynsymEntry*>(dynSym.begin);
	for (unsigned int i = 0; i < (rel.end - rel.begin) / sizeof(RelEntry); i++) {
		ptr_t* target = reinterpret_cast<ptr_t*>(base + res[i].offset);
		switch (res[i].flag) {
			case RelEntry::RELATIVE_TO_BASE:
				*target += base;
				break;
			case RelEntry::IMPORT_SYMBOL_DATA_OFFSET:
				*target += des[res[i].dynsymIndex].value;
				break;
			case RelEntry::IMPORT_SYMBOL_DATA:
			case RelEntry::IMPORT_SYMBOL_CODE:
				*target = des[res[i].dynsymIndex].value;
				break;
			default:
				std::abort();
		}
	}
}
}
// vim: foldmarker=<([{,}])> foldmethod=marker
